package se.webbzon.boltzmann.minigame.menu;

import java.awt.Image;
import java.util.ArrayList;
import java.util.Collection;

import se.webbzon.boltzmann.input.Button;
import se.webbzon.boltzmann.input.ButtonInfo;
import se.webbzon.boltzmann.input.Input;
import se.webbzon.boltzmann.input.InputListener;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldcamera.WorldCameraPane;
import se.webbzon.oschi01.worldobject.WorldObject;

public class Menu extends WorldObject {
	
	// The 2-dimensional depth of this menu
	private static final int depth = -2;
	
	// The number of buttons in this menu
	private static final int buttons = 5;
	
	// The layout of this menu
	private final MenuLayout layout;
	
	// The input controlling this menu
	private final Input input;
	private final ButtonInfo next, previous;
	
	// The input listener of this menu
	private final InputListener listener;
	
	// A collection of all listeners to this menu
	private final Collection<MenuListener> listeners;
	
	// The index of the selected item and the hovered item in this menu
	private int selectedIndex, hoveredIndex;
		
	/*============================================================
	Constructors
	============================================================*/

	public Menu(MenuLayout layout, Input input) {
		super(WorldObject.onCreate + WorldObject.onDestroy + WorldObject.onPostDraw, depth);
		this.layout = layout;
		this.input = input;
		this.next = input.getButtonInfo(Button.NEXT_ITEM);
		this.previous = input.getButtonInfo(Button.PREVIOUS_ITEM);
		this.listener = new InputListenerImpl();
		listeners = new ArrayList<MenuListener>();
		selectedIndex = 0;
		hoveredIndex = 0;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Adds a listener to this menu. **/
	public boolean addListener(MenuListener listener) {
		return listeners.add(listener);
	}
	
	/** Removes a listener from this menu. **/
	public boolean removeListener(MenuListener listener) {
		return listeners.remove(listener);
	}
	
	/** Clears all listeners from this menu. **/
	public void clearListeners() {
		listeners.clear();
	}
	
	/** Returns the index of the selected button. **/
	public int getSelection() {
		return selectedIndex;
	}
	
	/** Sets the selected button. **/
	public void setSelection(int selection) {
		MenuEvent event = new MenuEvent(this, selectedIndex, selection);
		for (MenuListener listener : listeners.toArray(new MenuListener[0])) {
			listener.onSelect(event);
		}
		if (selection < 0)
			this.selectedIndex = 0;
		else if (selection > buttons-1)
			this.selectedIndex = buttons-1;
		else
			this.selectedIndex = selection;
	}
	
	/** Returns the index of the hovered button. **/
	public int getHover() {
		return hoveredIndex;
	}
	
	/** Sets the hovered button. **/
	public void setHover(int hover) {
		if (hover < 0)
			this.hoveredIndex = 0;
		else if (hover > buttons-1)
			this.hoveredIndex = buttons-1;
		else
			this.hoveredIndex = hover;
	}
	
	@Override public void onCreate(WorldArea world) {
		input.addListener(listener);
	}

	@Override public void onDestroy(WorldArea world) {
		input.removeListener(listener);
	}
	
	@Override public void onPostDraw(WorldArea world, WorldCameraPane hud) {
		final int xOffset = layout.getXOffset();
		final int yOffset = layout.getYOffset();
		drawBackground(hud,xOffset,yOffset);
		drawButtons(hud,xOffset,yOffset);
		drawInfo(hud,xOffset,yOffset);
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Draws the menu background. **/
	private final void drawBackground(WorldCameraPane hud, int x, int y) {
		final Image bg = layout.getBackground();
		hud.drawImage(bg, x, y);
	}
	
	/** Draws the menu buttons. **/
	private final void drawButtons(WorldCameraPane hud, int x, int y) {
		int bx = x + layout.getButtonXOffset();
		final int by = y + layout.getButtonYOffset();
		for (int i = 0; i < buttons; i++) {
			final int index;
			final Image button;
			if (i == getSelection())
				index = 2;
			else if (i == getHover())
				index = 1;
			else
				index = 0;
			switch (i) {
			case 0: button = layout.getHomeButton().get(index); break;
			case 1: button = layout.getInfoButton().get(index); break;
			case 2: button = layout.getPlayButton().get(index); break;
			case 3: button = layout.getQuestionButton().get(index); break;
			default: button = layout.getExitButton().get(index); break;
			}
			hud.drawImage(button, bx, by);
			bx += layout.getButtonWidth() + layout.getButtonSpacing();
		}
	}
	
	/** Draws the menu info. **/
	private final void drawInfo(WorldCameraPane hud, int x, int y) {
		hud.drawImage(previous.getTextureSet().get(0).getImage(),x, y + 8);
		hud.drawImage(layout.getArrowLeft().get(0),x-48, y + 8);
		hud.drawImage(next.getTextureSet().get(0).getImage(),x + layout.getWidth()-32, y + 8);
		hud.drawImage(layout.getArrowRight().get(0),x + layout.getWidth() + 16, y + 8);
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	/** An implementation of an input listener. **/
	private final class InputListenerImpl implements InputListener {

		@Override public void primaryAxisChanged(Input input, double direction, double value) {};

		@Override public void secondaryAxisChanged(Input input, double direction, double value) {};

		@Override public void buttonPressed(Input input, Button button) {
			if (button == Button.NEXT_CHARACTER || button == Button.NEXT_ITEM) {
				setHover(getHover() + 1);
			} else if (button == Button.PREVIOUS_CHARACTER || button == Button.PREVIOUS_ITEM) {
				setHover(getHover() - 1);
			} else if (getSelection() != getHover() && button == Button.ACTION)
				setSelection(getHover());
		}

		@Override public void buttonReleased(Input input, Button button) {};

		@Override public void bindingAccepted(Input input, Button button) {};
		
	}

}
